home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 2
/
Nebula Two.iso
/
SourceCode
/
MiscKit1.7.1
/
MiscKit
/
Palettes
/
MiscTableScroll
/
MiscTableScroll.M
< prev
next >
Wrap
Text File
|
1996-02-11
|
65KB
|
2,012 lines
//=============================================================================
//
// Copyright (C) 1995, 1996 by Paul S. McCarthy and Eric Sunshine.
// Written by Paul S. McCarthy and Eric Sunshine.
// All Rights Reserved.
//
// This notice may not be removed from this source code.
//
// This object is included in the MiscKit by permission from the authors
// and its use is governed by the MiscKit license, found in the file
// "License.rtf" in the MiscKit distribution. Please refer to that file
// for a list of all applicable permissions and restrictions.
//
//=============================================================================
//-----------------------------------------------------------------------------
// MiscTableScroll.M
//
// ScrollView class that displays a 2-D table of cells.
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// $Id: MiscTableScroll.M,v 1.18 96/01/16 19:55:04 zarnuk Exp $
// $Log: MiscTableScroll.M,v $
// Revision 1.18 96/01/16 19:55:04 zarnuk
// Turns off display in -free.
// Does not call -update after calling -setAutodisplay:
// More careful about suppressing auto-sort after a drag.
//
// Revision 1.17 96/01/13 23:33:54 zarnuk
// Pulled-out sorting stuff into (Sort) category.
// New version (1), since range of sortType values increased.
// Plugged some memory leaks.
// No longer tries to resort when "skip" slots are dragged.
//
// Revision 1.16 95/12/19 23:16:38 sunshine
// Fixed MiscTableBorder.cc:1107: failed assertion
//
// Revision 1.15 95/12/17 15:11:35 zarnuk
// Added -border:sortSlot:, -sortCol:, -sortRow:.
//
// Revision 1.14 95/10/20 00:12:40 sunshine
// Was including MiscTableScroll.h and MiscTableCell.h with "" instead of <>.
//-----------------------------------------------------------------------------
#import <misckit/MiscTableScroll.h>
#import <misckit/MiscTableCell.h>
#import "MiscTableBorder.h"
#import "MiscTableView.h"
#import "MiscColView.h"
#import "MiscRowView.h"
#import "MiscNullView.h"
#import <new.h>
extern "Objective-C" {
#import <appkit/Application.h>
#import <appkit/Cell.h>
#import <appkit/ClipView.h>
#import <appkit/Font.h>
#import <appkit/FontManager.h>
}
extern "C" {
#import <assert.h>
#import <math.h>
#import <strings.h>
}
// There are no structural differences between versions 0 and 1. However,
// the range of the MiscSortType values increased from 0..8 to 0..12
#define MISC_TS_VERSION_0 0
#define MISC_TS_VERSION_1 1
#define MISC_TS_VERSION MISC_TS_VERSION_1
@implementation MiscTableScroll
//-----------------------------------------------------------------------------
// + initialize
//-----------------------------------------------------------------------------
+ initialize
{
if (self == [MiscTableScroll class])
{
[self setVersion: MISC_TS_VERSION];
}
return self;
}
//-----------------------------------------------------------------------------
// Tag Stuff
//-----------------------------------------------------------------------------
- (int) tag { return tag; }
- setTag:(int) x { tag = x; return self; }
//-----------------------------------------------------------------------------
// -nextText
//-----------------------------------------------------------------------------
- nextText { return nextText; }
- previousText { return previousText; }
- setNextText:obj
{
nextText = obj;
if (obj && [obj respondsTo: @selector(setPreviousText:)])
[obj setPreviousText: self];
return self;
}
- setPreviousText:obj { previousText = obj; return self; }
- (BOOL) isSelectable { return YES; }
- (BOOL) isEnabled { return enabled; }
- setEnabled:(BOOL)flag { enabled = flag; return self; }
- selectText:sender
{
if ([window firstResponder] != (id)tableView)
[window makeFirstResponder:tableView];
return self;
}
//-----------------------------------------------------------------------------
// Multicast Messages
//-----------------------------------------------------------------------------
- sendAction:(SEL)aSel to:obj forAllCells:(BOOL)flag
{
int const rlim = num_rows;
int const clim = num_cols;
for (int r = 0; r < rlim; r++)
for (int c = 0; c < clim; c++)
if (flag || [self cellIsSelected:r:c])
if (![obj perform:aSel with:[self cellAt:r:c]])
return self;
return self;
}
- (int) makeCellsPerform:(SEL)aSel with:p1 with:p2 selectedOnly:(BOOL)flag
{
int count = 0;
int const rlim = num_rows;
int const clim = num_cols;
for (int r = 0; r < rlim; r++)
for (int c = 0; c < clim; c++)
if (!flag || [self cellIsSelected:r:c])
{
id cell = [self cellAt:r:c];
if ([cell respondsTo:aSel])
if ([cell perform:aSel with:p1 with:p2])
count++;
else
return count;
}
return count;
}
- (int) makeCellsPerform:(SEL)aSel with:p1 selectedOnly:(BOOL)flag
{ return [self makeCellsPerform:aSel with:p1 with:0 selectedOnly:flag]; }
- (int) makeCellsPerform:(SEL)aSel selectedOnly:(BOOL)flag
{ return [self makeCellsPerform:aSel with:0 with:0 selectedOnly:flag]; }
- (int) makeCellsPerform:(SEL)aSel
{ return [self makeCellsPerform:aSel selectedOnly:NO]; }
- (int) makeCellsPerform:(SEL)aSel with:p1
{ return [self makeCellsPerform:aSel with:p1 selectedOnly:NO]; }
- (int) makeCellsPerform:(SEL)aSel with:p1 with:p2
{ return [self makeCellsPerform:aSel with:p1 with:p2 selectedOnly:NO];}
//-----------------------------------------------------------------------------
// FINDING CELLS
//-----------------------------------------------------------------------------
- (int) border:(MiscBorderType)b findSlotWithTag:(int)x
{
int const lim = (int) [self numSlots:b];
for (int i = 0; i < lim; i++)
if ([self border:b slotTag:i] == x)
return i;
return -1;
}
- (int) findColWithTag:(int)x
{ return [self border:MISC_COL_BORDER findSlotWithTag:x]; }
- (int) findRowWithTag:(int)x
{ return [self border:MISC_ROW_BORDER findSlotWithTag:x]; }
- findCell:cell row:(int*)row col:(int*)col
{
int const NRows = [self numRows];
int const NCols = [self numCols];
for (int r = 0; r < NRows; r++)
for (int c = 0; c < NCols; c++)
if ([self cellAt:r:c] == cell)
{
*row = r;
*col = c;
return self;
}
*row = -1;
*col = -1;
return 0;
}
- findCellWithTag:(int)x row:(int*)row col:(int*)col
{
int const NRows = [self numRows];
int const NCols = [self numCols];
for (int r = 0; r < NRows; r++)
for (int c = 0; c < NCols; c++)
{
id const cell = [self cellAt:r:c];
if (cell && [cell respondsTo:@selector(tag)] && [cell tag] == x)
{
*row = r;
*col = c;
return cell;
}
}
*row = -1;
*col = -1;
return 0;
}
- findCellWithTag:(int)x
{
int r, c;
return [self findCellWithTag:x row:&r col:&c];
}
//-----------------------------------------------------------------------------
// Selection stuff
//-----------------------------------------------------------------------------
- (MiscSelectionMode) selectionMode { return mode; }
- (void) setSelectionMode:(MiscSelectionMode) x
{
if (x != mode)
{
mode = x;
[colInfo.view setSelectionMode: mode];
[rowInfo.view setSelectionMode: mode];
[tableView setSelectionMode: mode];
}
}
- selectedCell { return 0; } // FIXME: write this
- (BOOL) borderHasSelection: (MiscBorderType)b
{ return info[b]->border->hasSelection(); }
- (BOOL) hasRowSelection { return [self borderHasSelection:MISC_ROW_BORDER]; }
- (BOOL) hasColSelection { return [self borderHasSelection:MISC_COL_BORDER]; }
- (BOOL) borderHasMultipleSelection: (MiscBorderType)b
{ return info[b]->border->hasMultipleSelection(); }
- (BOOL) hasMultipleRowSelection
{ return [self borderHasMultipleSelection: MISC_ROW_BORDER]; }
- (BOOL) hasMultipleColSelection
{ return [self borderHasMultipleSelection: MISC_COL_BORDER]; }
- (unsigned int) borderNumSelectedSlots: (MiscBorderType)b
{ return info[b]->border->numSelected(); }
- (unsigned int) numSelectedRows
{ return [self borderNumSelectedSlots: MISC_ROW_BORDER]; }
- (unsigned int) numSelectedCols
{ return [self borderNumSelectedSlots: MISC_COL_BORDER]; }
- (BOOL) border: (MiscBorderType)b slotIsSelected:(MiscCoord_P)slot
{ return info[b]->border->slotIsSelected( slot ); }
- (BOOL) rowIsSelected:(MiscCoord_P)row
{ return [self border:MISC_ROW_BORDER slotIsSelected:row]; }
- (BOOL) colIsSelected:(MiscCoord_P)col
{ return [self border:MISC_COL_BORDER slotIsSelected:col]; }
- (BOOL) cellIsSelected:(MiscCoord_P)r :(MiscCoord_P)c
{ return ([self rowIsSelected:r] || [self colIsSelected:c]); }
- (MiscCoord_P) borderSelectedSlot: (MiscBorderType)b
{ return info[b]->border->selectedSlot(); }
- (MiscCoord_P) selectedRow
{ return [self borderSelectedSlot:MISC_ROW_BORDER]; }
- (MiscCoord_P) selectedCol
{ return [self borderSelectedSlot:MISC_COL_BORDER]; }
- (void) border: (MiscBorderType)b selectedTags: (MiscIntList*)tags
{ info[b]->border->selectedTags( tags ); }
- (void) selectedRowTags: (MiscIntList*) tags
{ [self border:MISC_ROW_BORDER selectedTags:tags]; }
- (void) selectedColTags: (MiscIntList*) tags
{ [self border:MISC_COL_BORDER selectedTags:tags]; }
- (void) border: (MiscBorderType)b selectedSlots: (MiscIntList*)slots
{ info[b]->border->selectedSlots( slots ); }
- (void) selectedRows: (MiscIntList*) rows
{ [self border:MISC_ROW_BORDER selectedSlots:rows]; }
- (void) selectedCols: (MiscIntList*) cols
{ [self border:MISC_COL_BORDER selectedSlots:cols]; }
- (void) selectionChanged
{
if ([self isAutodisplay] && [self canDraw])
[self reflectSelection];
else
[self setNeedsDisplay:YES];
}
- (void) border: (MiscBorderType)b selectSlot:(MiscCoord_P)slot
{
BOOL changed = NO;
MiscTableBorder* const bp = info[b]->border;
unsigned int const n = bp->numSelected();
if (0 <= slot && slot < bp->count())
{
if (n != 1 || bp->selectedSlot() != slot)
{
bp->selectSlot( slot );
changed = YES;
}
}
else
{
if (n > 0)
{
bp->selectNone();
changed = YES;
}
}
if (changed)
[self selectionChanged];
}
- (void) selectRow:(MiscCoord_P)row
{ [self border:MISC_ROW_BORDER selectSlot:row]; }
- (void) selectCol:(MiscCoord_P)col
{ [self border:MISC_COL_BORDER selectSlot:col]; }
- (void) border: (MiscBorderType)b selectTags: (MiscIntList*)tags
{
info[b]->border->selectTags( tags );
[self selectionChanged];
}
- (void) selectRowTags: (MiscIntList*) tags
{ [self border:MISC_ROW_BORDER selectTags:tags]; }
- (void) selectColTags: (MiscIntList*) tags
{ [self border:MISC_COL_BORDER selectTags:tags]; }
- (void) border: (MiscBorderType)b selectSlots: (MiscIntList*)slots
{
info[b]->border->selectSlots( slots );
[self selectionChanged];
}
- (void) selectRows: (MiscIntList*) rows
{ [self border:MISC_ROW_BORDER selectSlots:rows]; }
- (void) selectCols: (MiscIntList*) cols;
{ [self border:MISC_COL_BORDER selectSlots:cols]; }
- (void) borderSelectAll: (MiscBorderType)b
{
if (mode == MISC_LIST_MODE || mode == MISC_HIGHLIGHT_MODE)
{
info[b]->border->selectAll();
[self selectionChanged];
}
}
- (void) selectAllRows { [self borderSelectAll: MISC_ROW_BORDER]; }
- (void) selectAllCols { [self borderSelectAll: MISC_COL_BORDER]; }
- selectAll:sender
{
[self selectAllRows];
[self sendActionIfEnabled];
return self;
}
- (void) borderClearSelection: (MiscBorderType)b
{
info[b]->border->selectNone();
[self selectionChanged];
}
- (void) clearRowSelection { [self borderClearSelection: MISC_ROW_BORDER]; }
- (void) clearColSelection { [self borderClearSelection: MISC_COL_BORDER]; }
- (void) clearSelection { [self clearRowSelection]; [self clearColSelection]; }
//-----------------------------------------------------------------------------
// Keyboard cursor stuff
//-----------------------------------------------------------------------------
- (void) reflectCursor { [tableView reflectCursor]; }
- (MiscCoord_P) borderCursor: (MiscBorderType)b
{ return info[b]->border->getCursor_P(); }
- (MiscCoord_P) cursorRow { return [self borderCursor: MISC_ROW_BORDER]; }
- (MiscCoord_P) cursorCol { return [self borderCursor: MISC_COL_BORDER]; }
- (void) border: (MiscBorderType)b setCursor: (MiscCoord_P) slot
{ info[b]->border->setCursor_P( slot ); [self reflectCursor]; }
- (void) setCursorRow: (MiscCoord_P) row
{ [self border: MISC_ROW_BORDER setCursor: row]; }
- (void) setCursorCol: (MiscCoord_P) col
{ [self border: MISC_COL_BORDER setCursor: col]; }
- (void) borderClearCursor: (MiscBorderType)b
{ info[b]->border->clearCursor(); [self reflectCursor]; }
- (void) clearCursorRow { [self borderClearCursor: MISC_ROW_BORDER]; }
- (void) clearCursorCol { [self borderClearCursor: MISC_COL_BORDER]; }
- (void) clearCursor { [self clearCursorRow]; [self clearCursorCol]; }
- (BOOL) borderHasValidCursor: (MiscBorderType)b
{ return info[b]->border->hasValidCursor(); }
- (BOOL) hasValidCursorRow
{ return [self borderHasValidCursor: MISC_ROW_BORDER]; }
- (BOOL) hasValidCursorCol
{ return [self borderHasValidCursor: MISC_COL_BORDER]; }
//-----------------------------------------------------------------------------
// Overrides... Scrollers are always required.
//-----------------------------------------------------------------------------
- setHorizScrollerRequired: (BOOL) flag { return self; }
- setVertScrollerRequired: (BOOL) flag { return self; }
//-----------------------------------------------------------------------------
// - getDocClipFrame:
//-----------------------------------------------------------------------------
- (void) getDocClipFrame: (NXRect*) rect
{
[contentView getFrame: rect];
}
//-----------------------------------------------------------------------------
// - freeBorder:
//-----------------------------------------------------------------------------
- (void) freeBorder:(MiscBorderInfo*)p
{
[p->view removeFromSuperview];
[p->view free];
[p->clip removeFromSuperview];
[p->clip free];
delete p->border;
}
//-----------------------------------------------------------------------------
// - free
//-----------------------------------------------------------------------------
- free
{
[self setAutodisplay:NO]; // Don't do any drawing!
[self emptyAndFreeCells];
[self freeBorder:&colInfo];
[self freeBorder:&rowInfo];
[nullView removeFromSuperview];
[nullView free];
[tableView removeFromSuperview];
[tableView free];
return [super free];
}
//-----------------------------------------------------------------------------
// get/set min/max total size limits.
//-----------------------------------------------------------------------------
- (NXCoord) totalSize:(MiscBorderType)b
{ return (NXCoord) info[b]->border->totalSize(); }
- (NXCoord) totalWidth
{ return [self totalSize:MISC_COL_BORDER]; }
- (NXCoord) totalHeight
{ return [self totalSize:MISC_ROW_BORDER]; }
- (NXCoord) minTotalSize:(MiscBorderType)b
{ return (NXCoord) info[b]->border->getMinTotalSize(); }
- (NXCoord) maxTotalSize:(MiscBorderType)b
{ return (NXCoord) info[b]->border->getMaxTotalSize(); }
- (NXCoord) minTotalWidth
{ return [self minTotalSize:MISC_COL_BORDER]; }
- (NXCoord) maxTotalWidth
{ return [self maxTotalSize:MISC_COL_BORDER]; }
- (NXCoord) minTotalHeight
{ return [self minTotalSize:MISC_ROW_BORDER]; }
- (NXCoord) maxTotalHeight
{ return [self maxTotalSize:MISC_ROW_BORDER]; }
// FIXME: Need to decide whether or not to update the views here.
// FIXME: Should check current value before setting.
- (void) border:(MiscBorderType)b setMinTotalSize:(NXCoord)size
{ info[b]->border->setMinTotalSize( (MiscPixels)floor(size) ); }
- (void) border:(MiscBorderType)b setMaxTotalSize:(NXCoord)size
{ info[b]->border->setMaxTotalSize( (MiscPixels)floor(size) ); }
- (void) setMinTotalWidth:(NXCoord)size
{ [self border:MISC_COL_BORDER setMinTotalSize:size]; }
- (void) setMaxTotalWidth:(NXCoord)size
{ [self border:MISC_COL_BORDER setMaxTotalSize:size]; }
- (void) setMinTotalHeight:(NXCoord)size
{ [self border:MISC_ROW_BORDER setMinTotalSize:size]; }
- (void) setMaxTotalHeight:(NXCoord)size
{ [self border:MISC_ROW_BORDER setMaxTotalSize:size]; }
//-----------------------------------------------------------------------------
// - constrainSize
//-----------------------------------------------------------------------------
- (void) constrainSize
{
NXRect r;
[self getDocClipFrame: &r];
if ([self minTotalSizeIsConstrained:MISC_COL_BORDER])
[self border:MISC_COL_BORDER setMinTotalSize: r.size.width];
if ([self maxTotalSizeIsConstrained:MISC_COL_BORDER])
[self border:MISC_COL_BORDER setMaxTotalSize: r.size.width];
if ([self minTotalSizeIsConstrained:MISC_ROW_BORDER])
[self border:MISC_ROW_BORDER setMinTotalSize: r.size.height];
if ([self maxTotalSizeIsConstrained:MISC_ROW_BORDER])
[self border:MISC_ROW_BORDER setMaxTotalSize: r.size.height];
[rowInfo.view adjustSize];
[colInfo.view adjustSize];
[tableView adjustSize];
}
//-----------------------------------------------------------------------------
// - sizeToCells
//-----------------------------------------------------------------------------
- sizeToCells
{
[self constrainSize];
return self;
}
//-----------------------------------------------------------------------------
// get/set min/max constrained
//-----------------------------------------------------------------------------
- (BOOL) minTotalSizeIsConstrained:(MiscBorderType)b
{ return info[b]->constrain_min; }
- (BOOL) maxTotalSizeIsConstrained:(MiscBorderType)b
{ return info[b]->constrain_max; }
- (BOOL) minTotalWidthIsConstrained
{ return [self minTotalSizeIsConstrained:MISC_COL_BORDER]; }
- (BOOL) maxTotalWidthIsConstrained
{ return [self maxTotalSizeIsConstrained:MISC_COL_BORDER]; }
- (BOOL) minTotalHeightIsConstrained
{ return [self minTotalSizeIsConstrained:MISC_ROW_BORDER]; }
- (BOOL) maxTotalHeightIsConstrained
{ return [self maxTotalSizeIsConstrained:MISC_ROW_BORDER]; }
- (void) border:(MiscBorderType)b constrainMinTotalSize:(BOOL)flag;
{
MiscBorderInfo* ip = info[b];
if (ip->constrain_min != flag)
{
ip->constrain_min = flag;
if (!flag)
[self border:MISC_COL_BORDER setMinTotalSize:0];
[self constrainSize];
}
}
- (void) border:(MiscBorderType)b constrainMaxTotalSize:(BOOL)flag
{
MiscBorderInfo* ip = info[b];
if (ip->constrain_max != flag)
{
ip->constrain_max = flag;
if (!flag)
[self border:MISC_COL_BORDER
setMaxTotalSize: (NXCoord) MISC_MAX_PIXELS_SIZE ];
[self constrainSize];
}
}
- (void) constrainMinTotalWidth:(BOOL)flag
{ [self border:MISC_COL_BORDER constrainMinTotalSize:flag]; }
- (void) constrainMaxTotalWidth:(BOOL)flag
{ [self border:MISC_COL_BORDER constrainMaxTotalSize:flag]; }
- (void) constrainMinTotalHeight:(BOOL)flag
{ [self border:MISC_ROW_BORDER constrainMinTotalSize:flag]; }
- (void) constrainMaxTotalHeight:(BOOL)flag
{ [self border:MISC_ROW_BORDER constrainMaxTotalSize:flag]; }
//-----------------------------------------------------------------------------
// - sizeTo::
//-----------------------------------------------------------------------------
- sizeTo:(NXCoord)width :(NXCoord)height
{
[super sizeTo:width:height];
[self constrainSize];
return self;
}
//-----------------------------------------------------------------------------
// - forwardBGColor
//-----------------------------------------------------------------------------
- (void) forwardBGColor
{
[super setBackgroundColor: backgroundColor];
[colInfo.clip setBackgroundColor: backgroundColor];
[rowInfo.clip setBackgroundColor: backgroundColor];
}
//-----------------------------------------------------------------------------
// - initBorder:type:
//-----------------------------------------------------------------------------
- (void) initBorder:(MiscBorderInfo*) p type:(MiscBorderType) type
{
NXZone* const z = [self zone];
if (p->border == 0)
p->border = new( NXZoneMalloc(z,sizeof(*(p->border))) )
MiscTableBorder( type );
p->border->setOwner( self );
if (type == MISC_COL_BORDER)
p->view = [[MiscColView allocFromZone:z]
initFrame:0 scroll:self info:p->border];
else
p->view = [[MiscRowView allocFromZone:z]
initFrame:0 scroll:self info:p->border];
p->clip = [[ClipView allocFromZone:z] initFrame:0];
[p->clip setDocView:p->view];
if (p->isOn)
{
[self addSubview: p->clip];
[window invalidateCursorRectsForView: p->view];
}
}
//-----------------------------------------------------------------------------
// - doInit:
//
// NOTE *1*: The tableView was initialized with an argument of 0 so it's
// frame is invalid. Calling constrainSize with an invalid frame
// can result in crashers when it tries to access slots outside
// of the appropriate area. Calling -tile first ensures that the
// frame is valid.
//-----------------------------------------------------------------------------
- (void) doInit:(int)ver
{
[window disableDisplay];
[self setBorderType: NX_BEZEL];
[super setHorizScrollerRequired: YES];
[super setVertScrollerRequired: YES];
info[ MISC_COL_BORDER ] = &colInfo;
info[ MISC_ROW_BORDER ] = &rowInfo;
[self initBorder:&colInfo type:MISC_COL_BORDER];
[self initBorder:&rowInfo type:MISC_ROW_BORDER];
NXZone* const z = [self zone];
tableView = [[MiscTableView allocFromZone:z] initFrame:0
scroll:self
colInfo:colInfo.border
rowInfo:rowInfo.border];
nullView = [[MiscNullView allocFromZone:z] initFrame:0];
if (colInfo.isOn && rowInfo.isOn)
[self addSubview:nullView];
id oldView = [self setDocView: tableView];
[oldView free];
[self tile]; // NOTE *1*
[self constrainSize];
[self forwardBGColor];
[self registerServicesTypes];
[window reenableDisplay];
}
//-----------------------------------------------------------------------------
// - initFrame:
//-----------------------------------------------------------------------------
- initFrame: (NXRect const*) frameRect
{
[super initFrame: frameRect];
font = [[self class] defaultFont];
tag = 0;
enabled = YES;
colInfo.border = 0; colInfo.isOn = YES;
colInfo.constrain_min = YES;
colInfo.constrain_max = NO;
rowInfo.border = 0; rowInfo.isOn = NO;
rowInfo.constrain_min = YES;
rowInfo.constrain_max = NO;
textColor = [[self class] defaultTextColor];
backgroundColor = [[self class] defaultBackgroundColor];
highlightTextColor = [[self class] defaultHighlightTextColor];
highlightBackgroundColor = [[self class] defaultHighlightBackgroundColor];
[self doInit:MISC_TS_VERSION];
if ([self respondsTo:@selector(initIB)]) [self perform:@selector(initIB)];
return self;
}
//-----------------------------------------------------------------------------
// - setFrame:
//-----------------------------------------------------------------------------
- setFrame: (NXRect const*) frameRect
{
[super setFrame:frameRect];
[self constrainSize];
return self;
}
//-----------------------------------------------------------------------------
// - adjustSizes
//-----------------------------------------------------------------------------
- (void) adjustSizes
{
if (colInfo.isOn && colInfo.view != 0)
[colInfo.view adjustSize];
if (rowInfo.isOn && rowInfo.view != 0)
[rowInfo.view adjustSize];
[tableView adjustSize];
}
//-----------------------------------------------------------------------------
// - tile
//-----------------------------------------------------------------------------
- tile
{
[window disableDisplay];
[super tile];
[self adjustSizes];
if (colInfo.isOn && !rowInfo.isOn)
{
NXCoord colHeight = [colInfo.view frameHeight];
NXRect colRect;
NXRect docRect;
[contentView getFrame: &docRect];
NXDivideRect( &docRect, &colRect, colHeight, NX_YMIN );
[colInfo.clip setFrame: &colRect];
[contentView setFrame: &docRect];
[window invalidateCursorRectsForView: colInfo.view];
}
else if (!colInfo.isOn && rowInfo.isOn)
{
NXCoord rowWidth = [rowInfo.view frameHeight];
NXRect rowRect;
NXRect docRect;
[contentView getFrame: &docRect];
NXDivideRect( &docRect, &rowRect, rowWidth, NX_XMIN );
[rowInfo.clip setFrame: &rowRect];
[contentView setFrame: &docRect];
[window invalidateCursorRectsForView: rowInfo.view];
}
else if (colInfo.isOn && rowInfo.isOn)
{
NXCoord colHeight = [colInfo.view frameHeight];
NXCoord rowWidth = [rowInfo.view frameHeight];
NXRect nulRect;
NXRect colRect;
NXRect rowRect;
NXRect docRect;
[contentView getFrame: &docRect];
NXDivideRect( &docRect, &colRect, colHeight, NX_YMIN );
NXDivideRect( &colRect, &nulRect, rowWidth, NX_XMIN );
NXDivideRect( &docRect, &rowRect, rowWidth, NX_XMIN );
[nullView setFrame: &nulRect];
[colInfo.clip setFrame: &colRect];
[rowInfo.clip setFrame: &rowRect];
[contentView setFrame: &docRect];
[window invalidateCursorRectsForView: colInfo.view];
[window invalidateCursorRectsForView: rowInfo.view];
}
[window reenableDisplay];
return self;
}
//-----------------------------------------------------------------------------
// - reflectScroll:
//-----------------------------------------------------------------------------
- reflectScroll: aView
{
if (aView == contentView) // only reflect position of contentView
[super reflectScroll: aView];
return self;
}
//-----------------------------------------------------------------------------
// - scrollClip:to:
//-----------------------------------------------------------------------------
- scrollClip: aClipView to: (const NXPoint *) aPoint
{
if (aClipView == contentView) // contentView only.
{
NXRect rect;
[window disableFlushWindow];
[aClipView rawScroll: aPoint]; // Scroll content
if (colInfo.isOn)
{
[colInfo.clip getBounds: &rect]; // Maybe scroll col headings.
if (rect.origin.x != aPoint->x)
{
rect.origin.x = aPoint->x;
[colInfo.clip rawScroll: &rect.origin];
[window invalidateCursorRectsForView: colInfo.view];
}
}
if (rowInfo.isOn)
{
[rowInfo.clip getBounds: &rect]; // Maybe scroll row labels.
if (rect.origin.y != aPoint->y)
{
rect.origin.y = aPoint->y;
[rowInfo.clip rawScroll: &rect.origin];
[window invalidateCursorRectsForView: rowInfo.view];
}
}
[[window reenableFlushWindow] flushWindow];
}
else if (aClipView == (id)colInfo.clip)
{
NXRect rect;
[contentView getBounds: &rect];
rect.origin.x = aPoint->x;
[self scrollClip:contentView to:&(rect.origin)];
[self reflectScroll:contentView];
}
else if (aClipView == (id)rowInfo.clip)
{
NXRect rect;
[contentView getBounds: &rect];
rect.origin.y = aPoint->y;
[self scrollClip:contentView to:&(rect.origin)];
[self reflectScroll:contentView];
}
return self;
}
//-----------------------------------------------------------------------------
// Delegate Stuff
//-----------------------------------------------------------------------------
- delegate { return delegate; }
- setDelegate:obj { delegate = obj; return self; }
- dataDelegate { return dataDelegate; }
- setDataDelegate:obj { dataDelegate = obj; return self; }
- (char const*) border:(MiscBorderType)b getDelegateSlotTitle:(int)slot
{
if (delegate != 0 &&
[delegate respondsTo:@selector(tableScroll:border:slotTitle:)])
return [delegate tableScroll:self border:b slotTitle:slot];
if (dataDelegate != 0 &&
[dataDelegate respondsTo:@selector(tableScroll:border:slotTitle:)])
return [dataDelegate tableScroll:self border:b slotTitle:slot];
return 0;
}
- border:(MiscBorderType)b getDelegateSlotPrototype:(int)s
{
if (delegate != 0 &&
[delegate respondsTo:@selector(tableScroll:border:slotPrototype:)])
return [delegate tableScroll:self border:b slotPrototype:s];
if (dataDelegate != 0 &&
[dataDelegate respondsTo:@selector(tableScroll:border:slotPrototype:)])
return [dataDelegate tableScroll:self border:b slotPrototype:s];
return 0;
}
- (void) border:(MiscBorderType)b slotDraggedFrom:(int)fromPos to:(int)toPos
{
MiscBorderType const ob = otherBorder(b);
if ([self autoSortSlots:ob])
{
int slot = [self border:b slotAtPosition:toPos];
if ([self border:b slotSortType:slot] != MISC_SORT_SKIP ||
[self border:b slotSortFunc:slot] != 0)
[self sortSlots:ob]; // Don't resort if it doesn't affect ordering.
}
if (delegate != 0 &&
[delegate respondsTo:@selector(tableScroll:border:slotDraggedFrom:to:)])
[delegate tableScroll:self border:b slotDraggedFrom:fromPos to:toPos];
}
- (void) border:(MiscBorderType)b slotResized:(int)n
{
if (delegate != 0 &&
[delegate respondsTo:@selector(tableScroll:border:slotResized:)])
[delegate tableScroll:self border:b slotResized:n];
}
//-----------------------------------------------------------------------------
// Target / Action
//-----------------------------------------------------------------------------
- target { return target; }
- setTarget:obj { target = obj; return self; }
- doubleTarget { return doubleTarget; }
- setDoubleTarget:obj { doubleTarget = obj; return self; }
- (SEL) action { return action; }
- setAction:(SEL)new_sel { action = new_sel; return self; }
- setDoubleAction:(SEL)new_sel { doubleAction = new_sel; return self; }
- (SEL) doubleAction { return doubleAction; }
- sendAction:(SEL)aSel to:obj
{
if (aSel == 0)
aSel = action;
if (obj == 0)
obj = target;
return ([NXApp sendAction:aSel to:obj from:self] ? self : 0);
}
- (SEL) getCellAction:cell
{
if ([cell respondsTo:@selector(action)])
return [cell action];
return 0;
}
- getCellTarget:cell
{
if ([cell respondsTo:@selector(target)])
return [cell target];
return 0;
}
- sendAction
{
id cell = [self selectedCell];
return [self sendAction:[self getCellAction:cell]
to:[self getCellTarget:cell]];
}
- sendDoubleAction
{
return [self sendAction:doubleAction to:doubleTarget];
}
- sendActionIfEnabled
{
if ([self isEnabled])
return [self sendAction];
return 0;
}
- sendDoubleActionIfEnabled
{
if ([self isEnabled])
return [self sendDoubleAction];
return 0;
}
//-----------------------------------------------------------------------------
// FONT
//-----------------------------------------------------------------------------
+ (Font*) defaultFont
{
return [Font userFontOfSize:12.0 matrix:NX_FLIPPEDMATRIX];
}
- font
{
return font;
}
static double get_height( Font* font )
{
NXFontMetrics const* const p = [font metrics];
double const size = [font pointSize];
return ((p->fontBBox[3] - p->fontBBox[1]) * size);
}
- setFont:newFont
{
if (newFont != 0 && newFont != (id)font && [newFont isKindOf:[Font class]])
{
[window disableDisplay];
Font* oldFont = font;
font = newFont;
NXCoord old_size = [self uniformSizeRows];
if (old_size != 0)
{
// FIXME: Handle this better. Different cell-types will have
// different amounts of "fixed-size" border stuff.
NXCoord const BORDER_THICKNESS = 1;
old_size -= BORDER_THICKNESS;
NXCoord const new_size =
floor( 0.5 + (double(old_size) *
(get_height( newFont ) / get_height( oldFont ))));
if (new_size != old_size)
[self setUniformSizeRows:(new_size + BORDER_THICKNESS)];
}
// FIXME: Set font in all existing prototype cells.
// WARNING: Currently, just asking the border for a prototype
// in a given slot allocates and initializes an array of prototypes.
if (![self isLazy]) // Eager beaver sets all cells now.
{
int const NRows = num_rows;
int const NCols = num_cols;
for (int r = 0; r < NRows; r++)
{
for (int c = 0; c < NCols; c++)
{
id cell = [self cellAt:r:c];
if (cell != 0)
{
if ([cell respondsTo:@selector(setOwnerFont:)])
[cell setOwnerFont:newFont];
else if ([cell respondsTo:@selector(setFont:)])
[cell setFont:newFont];
}
}
}
}
if (delegate != 0 &&
[delegate respondsTo:@selector(tableScroll:fontChangedFrom:to:)])
[delegate tableScroll:self fontChangedFrom:oldFont to:newFont];
if (dataDelegate != 0 &&
[dataDelegate respondsTo:
@selector(tableScroll:fontChangedFrom:to:)])
[dataDelegate tableScroll:self fontChangedFrom:oldFont to:newFont];
[window reenableDisplay];
[self update];
}
return self;
}
- changeFont:sender
{
FontManager* fontMgr = [FontManager new];
Font* newFont = [fontMgr convertFont:[fontMgr selFont]];
if (newFont != 0 && newFont != font)
{
[window disableDisplay];
Font* oldFont = font;
[self setFont:newFont];
if (delegate != 0 &&
[delegate respondsTo: @selector(tableScroll:changeFont:to:)])
[delegate tableScroll:self changeFont:oldFont to:newFont];
if (dataDelegate != 0 &&
[dataDelegate respondsTo: @selector(tableScroll:changeFont:to:)])
[dataDelegate tableScroll:self changeFont:oldFont to:newFont];
[window reenableDisplay];
[self update];
}
return self;
}
//-----------------------------------------------------------------------------
// COLOR
//
// The following macros expand into the implementations for these functions.
// Their names are listed so they can be found when searched for.
// setBackgroundColor:, setTextColor:,
// setHighlightBackgroundColor:, setHighlightTextColor:
// setBackgroundGray:, setTextGray:,
// setHighlightBackgroundGray:, setHighlightTextGray:
// backgroundGray:, textGray:, highlightBackgroundGray:, highlightTextGray:
//-----------------------------------------------------------------------------
+ (NXColor) defaultBackgroundColor { return NX_COLORLTGRAY; }
+ (NXColor) defaultTextColor { return NX_COLORBLACK; }
+ (NXColor) defaultHighlightBackgroundColor { return NX_COLORWHITE; }
+ (NXColor) defaultHighlightTextColor { return NX_COLORBLACK; }
- (NXColor) backgroundColor { return backgroundColor; }
- (NXColor) textColor { return textColor; }
- (NXColor) highlightBackgroundColor { return highlightBackgroundColor; }
- (NXColor) highlightTextColor { return highlightTextColor; }
- setColor:(NXColor) value { return [self setBackgroundColor:value]; }
- (NXColor) color { return [self backgroundColor]; }
- setColor:(NXColor)x // New color value.
var:(NXColor*)v // Instance variable for the color.
sel1:(SEL)sel1 // "setOwner...Color:" message for cell.
sel2:(SEL)sel2 // "set...Color:" message for cell.
notifySel:(SEL)notifySel // "..ColorChangedTo:" message
{
if (!NXEqualColor( x, *v ))
{
BOOL const was_auto = [self isAutodisplay];
[self setAutodisplay:NO];
*v = x;
if (v == &backgroundColor) [self forwardBGColor];
if (![self isLazy])
{
int const NRows = num_rows;
int const NCols = num_cols;
for (int r = 0; r < NRows; r++)
for (int c = 0; c < NCols; c++)
{
id cell = [self cellAt:r:c];
if (cell != 0)
{
if ([cell respondsTo:sel1])
(*[cell methodFor:sel1])( cell, sel1, x );
else if ([cell respondsTo:sel2])
(*[cell methodFor:sel2])( cell, sel2, x );
}
}
}
if (delegate != 0 && [delegate respondsTo:notifySel])
(*[delegate methodFor:notifySel])( delegate, notifySel, self, x );
if (dataDelegate != 0 && [dataDelegate respondsTo:notifySel])
(*[dataDelegate methodFor:notifySel])
( dataDelegate, notifySel, self, x );
[self setNeedsDisplay:YES];
[self setAutodisplay:was_auto]; // Will display if needed.
}
return self;
}
#define MISC_SET_COLOR_FUNC(LNAME,CNAME)\
- set##CNAME##Color: (NXColor) value\
{ return [self setColor:value\
var:& LNAME##Color\
sel1:@selector(setOwner##CNAME##Color:)\
sel2:@selector(set##CNAME##Color:)\
notifySel:@selector(tableScroll:LNAME##ColorChangedTo:)]; }
MISC_SET_COLOR_FUNC( background, Background )
MISC_SET_COLOR_FUNC( text, Text )
MISC_SET_COLOR_FUNC( highlightBackground, HighlightBackground )
MISC_SET_COLOR_FUNC( highlightText, HighlightText )
#undef MISC_SET_COLOR_FUNC
static inline float color_to_gray( NXColor x )
{
float gray;
NXConvertColorToGray( x, &gray );
return gray;
}
#define MISC_GET_GRAY_FUNC( LNAME )\
- (float) LNAME##Gray { return color_to_gray( [self LNAME##Color] ); }
MISC_GET_GRAY_FUNC( background )
MISC_GET_GRAY_FUNC( text )
MISC_GET_GRAY_FUNC( highlightBackground )
MISC_GET_GRAY_FUNC( highlightText )
#undef MISC_GET_GRAY_FUNC
#define MISC_SET_GRAY_FUNC( CNAME )\
- set##CNAME##Gray: (float) x\
{ return [self set##CNAME##Color: NXConvertGrayToColor(x)]; }
MISC_SET_GRAY_FUNC( Background )
MISC_SET_GRAY_FUNC( Text )
MISC_SET_GRAY_FUNC( HighlightBackground )
MISC_SET_GRAY_FUNC( HighlightText )
#undef MISC_SET_GRAY_FUNC
//-----------------------------------------------------------------------------
// SAVE / RESTORE
//-----------------------------------------------------------------------------
- border:(MiscBorderType)b slotOrder:(MiscIntList*)list
{
if (list != 0)
{
MiscTableBorder const* const bp = info[b]->border;
MiscCoord_P const* const vmap = bp->getVMap();
int const lim = bp->count();
[list empty];
for (int i = 0; i < lim; i++)
[list addInt: (vmap ? vmap[i] : i) ];
return self;
}
return 0;
}
- colOrder:(MiscIntList*)list
{ return [self border:MISC_COL_BORDER slotOrder:list]; }
- rowOrder:(MiscIntList*)list
{ return [self border:MISC_ROW_BORDER slotOrder:list]; }
- border:(MiscBorderType)b setSlotOrder:(MiscIntList*)list
{
id retval = 0;
if (list != 0)
{
MiscTableBorder* const bp = info[b]->border;
int const lim = bp->count();
if ([list count] == lim)
if (bp->setVMap( [list rawData] ))
{
MiscBorderType const ob = otherBorder(b);
if ([self autoSortSlots:ob])
[self sortSlots:ob];
retval = self;
}
}
return retval;
}
- setColOrder:(MiscIntList*)list
{ return [self border:MISC_COL_BORDER setSlotOrder:list]; }
- setRowOrder:(MiscIntList*)list
{ return [self border:MISC_ROW_BORDER setSlotOrder:list]; }
- (char*) border:(MiscBorderType)b slotOrderAsString:(char*)buff
size:(int)buff_size canExpand:(BOOL)canExpand
{
char* retval;
MiscIntList* list = [[MiscIntList alloc] init];
[self border:b slotOrder:list];
retval = [list writeToString:buff size:buff_size canExpand:canExpand];
[list free];
return retval;
}
- (char*) colOrderAsString:(char*)buff
size:(int)buff_size canExpand:(BOOL)canExpand
{ return [self border:MISC_COL_BORDER slotOrderAsString:buff
size:buff_size canExpand:canExpand]; }
- (char*) rowOrderAsString:(char*)buff
size:(int)buff_size canExpand:(BOOL)canExpand
{ return [self border:MISC_ROW_BORDER slotOrderAsString:buff
size:buff_size canExpand:canExpand]; }
- border:(MiscBorderType)b setSlotOrderFromString:(char const*)s
{
id retval;
MiscIntList* list = [[MiscIntList alloc] init];
[list readFromString:s];
retval = [self border:b setSlotOrder:list];
[list free];
return retval;
}
- setColOrderFromString:(char const*)s
{ return [self border:MISC_COL_BORDER setSlotOrderFromString:s]; }
- setRowOrderFromString:(char const*)s
{ return [self border:MISC_ROW_BORDER setSlotOrderFromString:s]; }
- border:(MiscBorderType)b slotSizes:(MiscIntList*)list
{
if (list != 0)
{
MiscTableBorder const* const bp = info[b]->border;
int const lim = bp->count();
[list empty];
for (int i = 0; i < lim; i++)
[list addInt: (int) bp->getSize_P( i ) ];
return self;
}
return 0;
}
- colSizes:(MiscIntList*)list
{ return [self border:MISC_COL_BORDER slotSizes:list]; }
- rowSizes:(MiscIntList*)list
{ return [self border:MISC_ROW_BORDER slotSizes:list]; }
- border:(MiscBorderType)b setSlotSizes:(MiscIntList*)list
{
if (list != 0)
{
MiscTableBorder* const bp = info[b]->border;
int const lim = bp->count();
if ([list count] == lim)
{
for (int i = 0; i < lim; i++)
bp->setSize_P( i, (MiscPixels) [list intAt:i] );
[self constrainSize];
return self;
}
}
return 0;
}
- setColSizes:(MiscIntList*)list
{ return [self border:MISC_COL_BORDER setSlotSizes:list]; }
- setRowSizes:(MiscIntList*)list
{ return [self border:MISC_ROW_BORDER setSlotSizes:list]; }
- (char*) border:(MiscBorderType)b slotSizesAsString:(char*)buff
size:(int)buff_size canExpand:(BOOL)canExpand
{
char* retval;
MiscIntList* list = [[MiscIntList alloc] init];
[self border:b slotSizes:list];
retval = [list writeToString:buff size:buff_size canExpand:canExpand];
[list free];
return retval;
}
- (char*) colSizesAsString:(char*)buff
size:(int)buff_size canExpand:(BOOL)canExpand
{ return [self border:MISC_COL_BORDER slotSizesAsString:buff
size:buff_size canExpand:canExpand]; }
- (char*) rowSizesAsString:(char*)buff
size:(int)buff_size canExpand:(BOOL)canExpand
{ return [self border:MISC_ROW_BORDER slotSizesAsString:buff
size:buff_size canExpand:canExpand]; }
- border:(MiscBorderType)b setSlotSizesFromString:(char const*)s
{
id retval;
MiscIntList* list = [[MiscIntList alloc] init];
[list readFromString:s];
retval = [self border:b setSlotSizes:list];
[list free];
return retval;
}
- setColSizesFromString:(char const*)s
{ return [self border:MISC_COL_BORDER setSlotSizesFromString:s]; }
- setRowSizesFromString:(char const*)s
{ return [self border:MISC_ROW_BORDER setSlotSizesFromString:s]; }
//-----------------------------------------------------------------------------
// Border Views
//-----------------------------------------------------------------------------
- (BOOL) setBorder:(MiscBorderType)type on:(BOOL)on
{
MiscBorderInfo& b = *(info[type]);
if (b.isOn != on)
{
BOOL const other_border_is_on = info[otherBorder(type)]->isOn;
b.isOn = on;
if (on)
{
[self addSubview: b.clip];
[window invalidateCursorRectsForView: b.view];
if (other_border_is_on)
[self addSubview: nullView];
}
else
{
[b.clip removeFromSuperview];
if (other_border_is_on)
[nullView removeFromSuperview];
}
[self tile];
[self constrainSize];
[self update];
return YES;
}
return NO;
}
//-----------------------------------------------------------------------------
// SLOT methods
//-----------------------------------------------------------------------------
- (MiscTableBorder*) border:(MiscBorderType)b
{ return info[b]->border; }
- (BOOL) border:(MiscBorderType)b setTitlesOn: (BOOL) on_off
{ return [self setBorder:b on:on_off]; }
- (BOOL) borderTitlesOn:(MiscBorderType)b
{ return info[b]->isOn; }
- (MiscTableTitleMode) borderTitleMode:(MiscBorderType)b
{ return info[b]->border->getTitleMode(); }
- (void) border:(MiscBorderType)b setTitleMode:(MiscTableTitleMode)x
{
MiscBorderInfo* const ip = info[b];
if (ip->border->setTitleMode(x) && ip->isOn && ip->border->count() > 0)
[ip->view update];
}
- border:(MiscBorderType)b moveSlotFrom:(int)fromPos to:(int)toPos
{ info[b]->border->moveFromTo(fromPos,toPos); return self; }
- (int) border:(MiscBorderType)b slotPosition:(int)n
{ return info[b]->border->physicalToVisual(n); }
- (int) border:(MiscBorderType)b slotAtPosition:(int)n
{ return info[b]->border->visualToPhysical(n); }
- (void) border:(MiscBorderType)b physicalToVisual:(MiscIntList*)list
{
for (unsigned int i = [list count]; i-- > 0; )
{
MiscCoord_P const p = [list intAt:i];
[list replaceIntAt:i with:[self border:b slotPosition:p]];
}
}
- (void) border:(MiscBorderType)b visualToPhysical:(MiscIntList*)list
{
for (unsigned int i = [list count]; i-- > 0; )
{
MiscCoord_V const v = [list intAt:i];
[list replaceIntAt:i with:[self border:b slotAtPosition:v]];
}
}
- (BOOL) sizeableSlots:(MiscBorderType)b
{ return info[b]->border->isSizeable(); }
- (BOOL) draggableSlots:(MiscBorderType)b
{ return info[b]->border->isDraggable(); }
- (BOOL) modifierDragSlots:(MiscBorderType)b
{ return info[b]->border->isModifierDrag(); }
- (NXCoord) uniformSizeSlots:(MiscBorderType)b
{ return (NXCoord) info[b]->border->getUniformSize(); }
- (NXCoord) border:(MiscBorderType)b slotAdjustedSize:(int)n
{ return (NXCoord) info[b]->border->effectiveSize_P(n); }
- (NXCoord) border:(MiscBorderType)b slotSize:(int)n
{ return (NXCoord) info[b]->border->getSize_P(n); }
- (NXCoord) border:(MiscBorderType)b slotMinSize:(int)n
{ return (NXCoord) info[b]->border->getMinSize_P(n); }
- (NXCoord) border:(MiscBorderType)b slotMaxSize:(int)n
{ return (NXCoord) info[b]->border->getMaxSize_P(n); }
- (NXCoord) border:(MiscBorderType)b slotDataSize:(int)n
{ return (NXCoord) info[b]->border->getDataSize_P(n); }
- (BOOL) border:(MiscBorderType)b slotIsSizeable:(int)n
{ return info[b]->border->isSizeable_P(n); }
- (BOOL) border:(MiscBorderType)b slotExpandsToData:(int)n
{ return info[b]->border->isData_P(n); }
- (BOOL) border:(MiscBorderType)b slotIsAutosize:(int)n
{ return info[b]->border->isSpringy_P(n); }
- (char const*) border:(MiscBorderType)b slotTitle:(int)n
{ return info[b]->border->getTitle_P(n); }
- (int) border:(MiscBorderType)b slotTag:(int)n
{ return info[b]->border->getTag_P(n); }
- (MiscTableCellStyle) border:(MiscBorderType)b slotCellType:(int)n
{ return info[b]->border->getStyle_P(n); }
- border:(MiscBorderType)b slotCellPrototype:(int)n
{ return info[b]->border->getPrototype_P(n); }
- (void) border:(MiscBorderType)b setSizeableSlots:(BOOL)flag
{ info[b]->border->setSizeable(flag); }
- (void) border:(MiscBorderType)b setDraggableSlots:(BOOL)flag
{ info[b]->border->setDraggable(flag); }
- (void) border:(MiscBorderType)b setModifierDragSlots:(BOOL)flag
{ info[b]->border->setModifierDrag(flag); }
- (void) border:(MiscBorderType)b setUniformSizeSlots:(NXCoord)uniform_size
{
MiscBorderInfo* const ip = info[b];
if (ip->border->setUniformSize((MiscPixels)floor(uniform_size)))
{
[self constrainSize];
if (b == MISC_ROW_BORDER)
{
[self setLineScroll:uniform_size];
[self setPageScroll:uniform_size];
}
[self update];
}
}
- (void) border:(MiscBorderType)b setSlot:(int)n size:(NXCoord)size
{
info[b]->border->setSize_P( n, (MiscPixels)floor(size) );
[self constrainSize];
}
- (void) border:(MiscBorderType)b setSlot:(int)n minSize:(NXCoord)size
{
info[b]->border->setMinSize_P( n, (MiscPixels)floor(size) );
[self constrainSize];
}
- (void) border:(MiscBorderType)b setSlot:(int)n maxSize:(NXCoord)size
{
info[b]->border->setMaxSize_P( n, (MiscPixels)floor(size) );
[self constrainSize];
}
- (void) border:(MiscBorderType)b setSlot:(int)n dataSize:(NXCoord)size
{ info[b]->border->setDataSize_P( n, (MiscPixels)floor(size) ); }
- (void) border:(MiscBorderType)b setSlot:(int)n sizeable:(BOOL)flag
{ info[b]->border->setSizeable_P( n, flag ); }
- (void) border:(MiscBorderType)b setSlot:(int)n expandsToData:(BOOL)flag
{ info[b]->border->setData_P( n, flag ); }
- (void) border:(MiscBorderType)b setSlot:(int)n autosize:(BOOL)flag
{
info[b]->border->setSpringy_P( n, flag );
[self constrainSize];
}
- (void) border:(MiscBorderType)b setSlot:(int)n title:(char const*)title
{
MiscBorderInfo* const ip = info[b];
if (ip->border->setTitle_P( n, title ) && ip->isOn)
[self border:b drawSlotTitle:n];
}
- (void) border:(MiscBorderType)b setSlot:(int)n tag:(int)x
{ info[b]->border->setTag_P( n, x ); }
- (void) border:(MiscBorderType)b setSlot:(int)n
cellType:(MiscTableCellStyle)type
{ info[b]->border->setStyle_P(n,type); }
- (void) border:(MiscBorderType)b setSlot:(int)n cellPrototype:p
{ info[b]->border->setPrototype_P(n,p); }
//-----------------------------------------------------------------------------
// COL methods
//-----------------------------------------------------------------------------
- (MiscTableBorder*) colBorder
{ return colInfo.border; }
- (BOOL) colTitlesOn
{ return [self borderTitlesOn:MISC_COL_BORDER]; }
- (BOOL) setColTitlesOn:(BOOL)x
{ return [self setBorder:MISC_COL_BORDER on:x]; }
- (MiscTableTitleMode) colTitleMode
{ return [self borderTitleMode:MISC_COL_BORDER]; }
- (void) setColTitleMode:(MiscTableTitleMode)x
{ [self border:MISC_COL_BORDER setTitleMode:x]; }
- moveColFrom:(int)fromPos to:(int)toPos
{ return [self border:MISC_COL_BORDER moveSlotFrom:fromPos to:toPos]; }
- (int) colPosition:(int)n
{ return [self border:MISC_COL_BORDER slotPosition:n]; }
- (int) colAtPosition:(int)n
{ return [self border:MISC_COL_BORDER slotAtPosition:n]; }
- (BOOL) sizeableCols
{ return [self sizeableSlots:MISC_COL_BORDER]; }
- (BOOL) draggableCols
{ return [self draggableSlots:MISC_COL_BORDER]; }
- (BOOL) modifierDragCols
{ return [self modifierDragSlots:MISC_COL_BORDER]; }
- (NXCoord) uniformSizeCols
{ return [self uniformSizeSlots:MISC_COL_BORDER]; }
- (NXCoord) colAdjustedSize:(int)n
{ return [self border:MISC_COL_BORDER slotAdjustedSize:n]; }
- (NXCoord) colSize:(int)n
{ return [self border:MISC_COL_BORDER slotSize:n]; }
- (NXCoord) colMinSize:(int)n
{ return [self border:MISC_COL_BORDER slotMinSize:n]; }
- (NXCoord) colMaxSize:(int)n
{ return [self border:MISC_COL_BORDER slotMaxSize:n]; }
- (NXCoord) colDataSize:(int)n
{ return [self border:MISC_COL_BORDER slotDataSize:n]; }
- (BOOL) colIsSizeable:(int)n
{ return [self border:MISC_COL_BORDER slotIsSizeable:n]; }
- (BOOL) colExpandsToData:(int)n
{ return [self border:MISC_COL_BORDER slotExpandsToData:n]; }
- (BOOL) colIsAutosize:(int)n
{ return [self border:MISC_COL_BORDER slotIsAutosize:n]; }
- (char const*) colTitle:(int)n
{ return [self border:MISC_COL_BORDER slotTitle:n]; }
- (int) colTag:(int)n
{ return [self border:MISC_COL_BORDER slotTag:n]; }
- (MiscTableCellStyle) colCellType:(int)n
{ return [self border:MISC_COL_BORDER slotCellType:n]; }
- colCellPrototype:(int)n
{ return [self border:MISC_COL_BORDER slotCellPrototype:n]; }
- (void) setSizeableCols:(BOOL)flag
{ [self border:MISC_COL_BORDER setSizeableSlots:flag]; }
- (void) setDraggableCols:(BOOL)flag
{ [self border:MISC_COL_BORDER setDraggableSlots:flag]; }
- (void) setModifierDragCols:(BOOL)flag
{ [self border:MISC_COL_BORDER setModifierDragSlots:flag]; }
- (void) setUniformSizeCols:(NXCoord)size
{ [self border:MISC_COL_BORDER setUniformSizeSlots:size]; }
- (void) setCol:(int)n size:(NXCoord)size
{ [self border:MISC_COL_BORDER setSlot:n size:size]; }
- (void) setCol:(int)n minSize:(NXCoord)size
{ [self border:MISC_COL_BORDER setSlot:n minSize:size]; }
- (void) setCol:(int)n maxSize:(NXCoord)size
{ [self border:MISC_COL_BORDER setSlot:n maxSize:size]; }
- (void) setCol:(int)n dataSize:(NXCoord)size
{ [self border:MISC_COL_BORDER setSlot:n dataSize:size]; }
- (void) setCol:(int)n sizeable:(BOOL)flag
{ [self border:MISC_COL_BORDER setSlot:n sizeable:flag]; }
- (void) setCol:(int)n expandsToData:(BOOL)flag
{ [self border:MISC_COL_BORDER setSlot:n expandsToData:flag]; }
- (void) setCol:(int)n autosize:(BOOL)flag
{ [self border:MISC_COL_BORDER setSlot:n autosize:flag]; }
- (void) setCol:(int)n title:(char const*)title
{ [self border:MISC_COL_BORDER setSlot:n title:title]; }
- (void) setCol:(int)n tag:(int)x
{ [self border:MISC_COL_BORDER setSlot:n tag:x]; }
- (void) setCol:(int)n cellType:(MiscTableCellStyle)x
{ [self border:MISC_COL_BORDER setSlot:n cellType:x]; }
- (void) setCol:(int)n cellPrototype:p
{ [self border:MISC_COL_BORDER setSlot:n cellPrototype:p]; }
//-----------------------------------------------------------------------------
// ROW methods
//-----------------------------------------------------------------------------
- (MiscTableBorder*) rowBorder
{ return rowInfo.border; }
- (BOOL) rowTitlesOn
{ return [self borderTitlesOn:MISC_ROW_BORDER]; }
- (BOOL) setRowTitlesOn:(BOOL)x
{ return [self setBorder:MISC_ROW_BORDER on:x]; }
- (MiscTableTitleMode) rowTitleMode
{ return [self borderTitleMode:MISC_ROW_BORDER]; }
- (void) setRowTitleMode:(MiscTableTitleMode)x
{ [self border:MISC_ROW_BORDER setTitleMode:x]; }
- moveRowFrom:(int)fromPos to:(int)toPos
{ return [self border:MISC_ROW_BORDER moveSlotFrom:fromPos to:toPos]; }
- (int) rowPosition:(int)n
{ return [self border:MISC_ROW_BORDER slotPosition:n]; }
- (int) rowAtPosition:(int)n
{ return [self border:MISC_ROW_BORDER slotAtPosition:n]; }
- (BOOL) sizeableRows
{ return [self sizeableSlots:MISC_ROW_BORDER]; }
- (BOOL) draggableRows
{ return [self draggableSlots:MISC_ROW_BORDER]; }
- (BOOL) modifierDragRows
{ return [self modifierDragSlots:MISC_ROW_BORDER]; }
- (NXCoord) uniformSizeRows
{ return [self uniformSizeSlots:MISC_ROW_BORDER]; }
- (NXCoord) rowAdjustedSize:(int)n
{ return [self border:MISC_ROW_BORDER slotAdjustedSize:n]; }
- (NXCoord) rowSize:(int)n
{ return [self border:MISC_ROW_BORDER slotSize:n]; }
- (NXCoord) rowMinSize:(int)n
{ return [self border:MISC_ROW_BORDER slotMinSize:n]; }
- (NXCoord) rowMaxSize:(int)n
{ return [self border:MISC_ROW_BORDER slotMaxSize:n]; }
- (NXCoord) rowDataSize:(int)n
{ return [self border:MISC_ROW_BORDER slotDataSize:n]; }
- (BOOL) rowIsSizeable:(int)n
{ return [self border:MISC_ROW_BORDER slotIsSizeable:n]; }
- (BOOL) rowExpandsToData:(int)n
{ return [self border:MISC_ROW_BORDER slotExpandsToData:n]; }
- (BOOL) rowIsAutosize:(int)n
{ return [self border:MISC_ROW_BORDER slotIsAutosize:n]; }
- (char const*) rowTitle:(int)n
{ return [self border:MISC_ROW_BORDER slotTitle:n]; }
- (int) rowTag:(int)n
{ return [self border:MISC_ROW_BORDER slotTag:n]; }
- (MiscTableCellStyle) rowCellType:(int)n
{ return [self border:MISC_ROW_BORDER slotCellType:n]; }
- rowCellPrototype:(int)n
{ return [self border:MISC_ROW_BORDER slotCellPrototype:n]; }
- (void) setSizeableRows:(BOOL)flag
{ [self border:MISC_ROW_BORDER setSizeableSlots:flag]; }
- (void) setDraggableRows:(BOOL)flag
{ [self border:MISC_ROW_BORDER setDraggableSlots:flag]; }
- (void) setModifierDragRows:(BOOL)flag
{ [self border:MISC_ROW_BORDER setModifierDragSlots:flag]; }
- (void) setUniformSizeRows:(NXCoord)size
{ [self border:MISC_ROW_BORDER setUniformSizeSlots:size]; }
- (void) setRow:(int)n size:(NXCoord)size
{ [self border:MISC_ROW_BORDER setSlot:n size:size]; }
- (void) setRow:(int)n minSize:(NXCoord)size
{ [self border:MISC_ROW_BORDER setSlot:n minSize:size]; }
- (void) setRow:(int)n maxSize:(NXCoord)size
{ [self border:MISC_ROW_BORDER setSlot:n maxSize:size]; }
- (void) setRow:(int)n dataSize:(NXCoord)size
{ [self border:MISC_ROW_BORDER setSlot:n dataSize:size]; }
- (void) setRow:(int)n sizeable:(BOOL)flag
{ [self border:MISC_ROW_BORDER setSlot:n sizeable:flag]; }
- (void) setRow:(int)n expandsToData:(BOOL)flag
{ [self border:MISC_ROW_BORDER setSlot:n expandsToData:flag]; }
- (void) setRow:(int)n autosize:(BOOL)flag
{ [self border:MISC_ROW_BORDER setSlot:n autosize:flag]; }
- (void) setRow:(int)n title:(char const*)title
{ [self border:MISC_ROW_BORDER setSlot:n title:title]; }
- (void) setRow:(int)n tag:(int)x
{ [self border:MISC_ROW_BORDER setSlot:n tag:x]; }
- (void) setRow:(int)n cellType:(MiscTableCellStyle)x
{ [self border:MISC_ROW_BORDER setSlot:n cellType:x]; }
- (void) setRow:(int)n cellPrototype:p
{ [self border:MISC_ROW_BORDER setSlot:n cellPrototype:p]; }
//-----------------------------------------------------------------------------
// - read:selector:
//-----------------------------------------------------------------------------
- (SEL) read:(int)ver selector:(NXTypedStream*)stream
{
SEL cmd = 0;
char* str;
NXReadType( stream, @encode(char*), &str );
if (str != 0)
{
if (*str != '\0')
cmd = sel_getUid( str );
free( str );
}
return cmd;
}
//-----------------------------------------------------------------------------
// - read:globalInfo:
//
// NOTE: Cannot archive sort_entry_func and sort_slot_func because they
// are function addresses.
//-----------------------------------------------------------------------------
- (void) read:(int)ver globalInfo:(NXTypedStream*)stream
{
NXReadType( stream, @encode(int), &tag );
NXReadType( stream, @encode(BOOL), &enabled );
NXReadType( stream, @encode(BOOL), &lazy );
NXReadType( stream, @encode(MiscSelectionMode), &mode );
font = NXReadObject( stream );
textColor = NXReadColor( stream );
backgroundColor = NXReadColor( stream );
highlightTextColor = NXReadColor( stream );
highlightBackgroundColor = NXReadColor( stream );
nextText = NXReadObject( stream );
previousText= NXReadObject( stream );
delegate = NXReadObject( stream );
dataDelegate= NXReadObject( stream );
target = NXReadObject( stream );
doubleTarget= NXReadObject( stream );
action = [self read:ver selector:stream];
doubleAction = [self read:ver selector:stream];
}
//-----------------------------------------------------------------------------
// - read:border:stream:
//-----------------------------------------------------------------------------
- (void) read:(int)ver border:(MiscBorderInfo*)p stream:(NXTypedStream*)stream
{
NXZone* const z = [self zone];
int n;
if (p->sort_vector != 0)
NXZoneFree( z, p->sort_vector );
NXReadType( stream, @encode(int), &(n) );
if (n > 0)
{
p->sort_vector_len = n;
p->sort_vector = (int*) NXZoneMalloc( z, n * sizeof(int) );
for (int i = 0; i < n; i++)
NXReadType( stream, @encode(int), &(p->sort_vector[i]) );
}
else
{
p->sort_vector_len = 0;
p->sort_vector = 0;
}
NXReadType( stream, @encode(BOOL), &(p->isOn) );
NXReadType( stream, @encode(BOOL), &(p->autoSort) );
NXReadType( stream, @encode(BOOL), &(p->constrain_min) );
NXReadType( stream, @encode(BOOL), &(p->constrain_max) );
if (p->border == 0)
p->border = new( NXZoneMalloc( z, sizeof(*(p->border)) ) )
MiscTableBorder( MISC_ROW_BORDER );
p->border->read( stream ); // FIXME: Should send ver.
}
//-----------------------------------------------------------------------------
// - read:cells:
//
// FIXME: What happens when a non-empty non-lazy TableScroll reads the data
// from a lazy, empty one. Does the memory get freed?
//-----------------------------------------------------------------------------
- (void) read:(int)ver cells: (NXTypedStream*) stream
{
NXReadType( stream, @encode(int), &num_cols );
NXReadType( stream, @encode(int), &num_rows );
max_rows = num_rows;
if (lazy)
{
max_cells = 0;
cells = 0;
}
else // (!lazy)
{
max_cells = max_rows * num_cols;
if (max_cells == 0)
cells = 0;
else
{
int const nbytes = max_cells * sizeof(*cells);
cells = (id*) NXZoneMalloc( [self zone], nbytes );
id* p = cells;
for (int r = 0; r < num_rows; r++)
for (int c = 0; c < num_cols; c++)
*p++ = NXReadObject( stream );
}
}
}
//-----------------------------------------------------------------------------
// - read:
//-----------------------------------------------------------------------------
- read: (NXTypedStream*) stream
{
[super read:stream];
char const* class_name = [[MiscTableScroll class] name];
int ver = NXTypedStreamClassVersion( stream, class_name );
if (((unsigned int)ver) > ((unsigned int)MISC_TS_VERSION))
[self error:"%s: old library (version %d), can't -read: "
"new object (version %d).\n",
class_name,
MISC_TS_VERSION, ver ];
[self read:ver globalInfo:stream];
[self read:ver border:&colInfo stream:stream];
[self read:ver border:&rowInfo stream:stream];
[self read:ver cells:stream];
[self doInit:ver];
return self;
}
//-----------------------------------------------------------------------------
// - writeSelector:stream:
//-----------------------------------------------------------------------------
- (void) writeSelector: (SEL) cmd stream: (NXTypedStream*) stream
{
char const* str = 0;
if (cmd != 0)
str = sel_getName( cmd );
if (str == 0) // not an 'else if'
str = "";
NXWriteType( stream, @encode(char*), &str );
}
//-----------------------------------------------------------------------------
// - writeGlobalInfo:
//
// NOTE: Cannot archive sort_entry_func and sort_slot_func because they
// are function addresses.
//-----------------------------------------------------------------------------
- (void) writeGlobalInfo: (NXTypedStream*) stream
{
NXWriteType( stream, @encode(int), &tag );
NXWriteType( stream, @encode(BOOL), &enabled );
NXWriteType( stream, @encode(BOOL), &lazy );
NXWriteType( stream, @encode(MiscSelectionMode), &mode );
NXWriteObject( stream, font );
NXWriteColor( stream, textColor );
NXWriteColor( stream, backgroundColor );
NXWriteColor( stream, highlightTextColor );
NXWriteColor( stream, highlightBackgroundColor );
NXWriteObjectReference( stream, nextText );
NXWriteObjectReference( stream, previousText );
NXWriteObjectReference( stream, delegate );
NXWriteObjectReference( stream, dataDelegate );
NXWriteObjectReference( stream, target );
NXWriteObjectReference( stream, doubleTarget );
[self writeSelector: action stream: stream];
[self writeSelector: doubleAction stream: stream];
}
//-----------------------------------------------------------------------------
// - writeBorder:stream:
//-----------------------------------------------------------------------------
- (void) writeBorder:(MiscBorderInfo*)p stream:(NXTypedStream*)stream
{
int const n = p->sort_vector_len;
NXWriteType( stream, @encode(int), &(n) );
if (n > 0)
for (int i = 0; i < n; i++)
NXWriteType( stream, @encode(int), &(p->sort_vector[i]) );
NXWriteType( stream, @encode(BOOL), &(p->isOn) );
NXWriteType( stream, @encode(BOOL), &(p->autoSort) );
NXWriteType( stream, @encode(BOOL), &(p->constrain_min) );
NXWriteType( stream, @encode(BOOL), &(p->constrain_max) );
p->border->write( stream );
}
//-----------------------------------------------------------------------------
// - writeCells:
//-----------------------------------------------------------------------------
- (void) writeCells: (NXTypedStream*) stream
{
NXWriteType( stream, @encode(int), &num_cols );
NXWriteType( stream, @encode(int), &num_rows );
if (!lazy)
for (int r = 0; r < num_rows; r++)
for (int c = 0; c < num_cols; c++)
NXWriteObject( stream, [self cellAt:r:c] );
}
//-----------------------------------------------------------------------------
// - write:
//-----------------------------------------------------------------------------
- write: (NXTypedStream*) stream
{
// Ensure that subviews are NOT archived.
if (colInfo.isOn) [colInfo.clip removeFromSuperview];
if (rowInfo.isOn) [rowInfo.clip removeFromSuperview];
if (rowInfo.isOn && colInfo.isOn) [nullView removeFromSuperview];
[tableView removeFromSuperview];
[super write:stream];
[self writeGlobalInfo:stream];
[self writeBorder:&colInfo stream:stream];
[self writeBorder:&rowInfo stream:stream];
[self writeCells:stream];
// Restore state.
[self setDocView: tableView];
if (colInfo.isOn) [self addSubview:colInfo.clip];
if (rowInfo.isOn) [self addSubview:rowInfo.clip];
if (rowInfo.isOn && colInfo.isOn) [self addSubview:nullView];
return self;
}
//-----------------------------------------------------------------------------
// DRAWING
//-----------------------------------------------------------------------------
- drawCellAt:(int)row :(int)col
{
[tableView drawCellAt:row:col];
[window flushWindow];
return self;
}
- drawRow:(int)row
{
[tableView drawRow:row];
[window flushWindow];
return self;
}
- drawCol:(int)col
{
[tableView drawCol:col];
[window flushWindow];
return self;
}
- border:(MiscBorderType)b drawSlot:(int)n
{ return (b == MISC_COL_BORDER) ? [self drawCol:n] : [self drawRow:n]; }
- border:(MiscBorderType)b drawSlotTitle:(int)n // physical position.
{
MiscBorderInfo* const ip = info[b];
if (ip->isOn) // visual position.
{
[ip->view drawSlot: [self border:b slotPosition:n]];
[window flushWindow];
}
return self;
}
- drawRowTitle:(int)n { return [self border:MISC_ROW_BORDER drawSlotTitle:n]; }
- drawColTitle:(int)n { return [self border:MISC_COL_BORDER drawSlotTitle:n]; }
- (void) reflectSelection
{
if ([self canDraw])
{
[window disableFlushWindow];
[rowInfo.view reflectSelection];
[colInfo.view reflectSelection];
[tableView reflectSelection];
[[window reenableFlushWindow] flushWindow];
}
else
[self setNeedsDisplay:YES];
}
- setAutodisplay:(BOOL) x
{
[rowInfo.view setAutodisplay:x];
[colInfo.view setAutodisplay:x];
[tableView setAutodisplay:x];
return [super setAutodisplay:x];
}
- (void) scrollCellToVisible: (int)row : (int) col
{ [tableView scrollCellToVisible: row:col]; }
- (void) scrollRowToVisible: (int)row { [tableView scrollRowToVisible:row]; }
- (void) scrollColToVisible: (int)col { [tableView scrollColToVisible:col]; }
- scrollSelToVisible
{
if ([self hasRowSelection])
[self scrollRowToVisible: [self selectedRow]];
else if ([self hasColSelection])
[self scrollColToVisible: [self selectedCol]];
return self;
}
//-----------------------------------------------------------------------------
// MOUSE & KEYBOARD TRACKING
//-----------------------------------------------------------------------------
- (void) trackBy: (MiscBorderType)b { [tableView trackBy:b]; }
- (MiscBorderType) trackingBy { return [tableView trackingBy]; }
@end